package belf.migrate.api.table.schema;

import belf.migrate.api.model.QualifiersModel;
import belf.migrate.api.util.*;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

@Getter
@EqualsAndHashCode
@RequiredArgsConstructor
public final class TablePath implements Serializable {
    private static final long serialVersionUID = 1L;
    private final String databaseName;
    private final String schemaName;
    private final String tableName;
    private final QualifiersModel qualifiersModel;

    public static final TablePath DEFAULT = TablePath.of("default",
            "default",
            "default",
            new QualifiersModel(QuoteType.NONE.getValue(), QuoteType.NONE.getValue(), FieldCase.ORIGINAL, QualifiedType.DOT));


    public static TablePath of(String fullName, boolean schemaFirst, QualifiersModel qualifiersModel) {
        String[] paths = fullName.split("\\.");

        if (paths.length == 1) {
            return of(null, paths[0], qualifiersModel);
        }
        if (paths.length == 2) {
            if (schemaFirst) {
                return of(null, paths[0], paths[1], qualifiersModel);
            }
            return of(paths[0], null, paths[1], qualifiersModel);
        }
        if (paths.length == 3) {
            return of(paths[0], paths[1], paths[2], qualifiersModel);
        }
        throw new IllegalArgumentException(
                String.format("Cannot get split '%s' to get databaseName and tableName", fullName));
    }

    public static TablePath of(String databaseName, String tableName, QualifiersModel qualifiersModel) {
        return of(databaseName, null, tableName, qualifiersModel);
    }

    public static TablePath of(String databaseName, String schemaName, String tableName, QualifiersModel qualifiersModel) {
        return new TablePath(databaseName, schemaName, tableName, qualifiersModel);
    }

    public String getSchemaAndTableName() {
        String quoteLeft = qualifiersModel.getLeftQuote();
        String quoteRight = qualifiersModel.getRightQuote();
        return getNameCommon(
                null,
                schemaName,
                tableName,
                quoteLeft,
                quoteRight,
                qualifiersModel.getFieldCase(),
                qualifiersModel.getQualifiedType());
    }

    public String getDatabaseAndTableName() {
        String quoteLeft = qualifiersModel.getLeftQuote();
        String quoteRight = qualifiersModel.getRightQuote();
        return getNameCommon(
                databaseName,
                null,
                tableName,
                quoteLeft,
                quoteRight,
                qualifiersModel.getFieldCase(),
                qualifiersModel.getQualifiedType());
    }

    public String getRightDatabaseName() {
        return databaseName == null ? schemaName : databaseName;
    }

    public String getFullName() {
        return getNameCommon(databaseName, schemaName, tableName, null, null, qualifiersModel.getFieldCase(), qualifiersModel.getQualifiedType());
    }

    public String getFullNameWithQuoted() {
        String quoteLeft = qualifiersModel.getLeftQuote();
        String quoteRight = qualifiersModel.getRightQuote();
        return getNameCommon(
                databaseName,
                schemaName,
                tableName,
                quoteLeft,
                quoteRight,
                qualifiersModel.getFieldCase(),
                qualifiersModel.getQualifiedType());
    }

    private String getNameCommon(
            String databaseName,
            String schemaName,
            String tableName,
            String quoteLeft,
            String quoteRight,
            FieldCase fieldCase,
            QualifiedType qualifiedType) {
        List<String> joinList = new ArrayList<>();
        quoteLeft = quoteLeft == null ? "" : quoteLeft;
        quoteRight = quoteRight == null ? "" : quoteRight;

        if (databaseName != null) {
            joinList.add(quoteLeft + databaseName + quoteRight);
        }

        if (schemaName != null) {
            joinList.add(quoteLeft + schemaName + quoteRight);
        }

        if (tableName != null) {
            joinList.add(quoteLeft + CatalogUtils.getFieldCase(tableName, fieldCase.getValue()) + quoteRight);
        }

        return String.join(qualifiedType.getValue(), joinList);
    }

    public String getCaseTableName() {
        if (QuoteType.NONE.getValue().equals(qualifiersModel.getLeftQuote())) {
            return tableName;
        }
        return CatalogUtils.getFieldCase(tableName, qualifiersModel.getFieldCase().getValue());
    }

    @Override
    public String toString() {
        return getFullName();
    }
}
